﻿using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto;
using System.Text;
using System;

namespace DotNetCommon.Test.Encrypt
{
    public class BouncyCastleDes
    {

        IBlockCipher engine = new DesEngine();

        /// <summary>
        /// 使用DES加密，key输入密码的时候，必须使用英文字符，区分大小写，且字符数量是8个，不能多也不能少
        /// </summary>
        /// <param name="plainText">需要加密的字符串</param>
        /// <param name="keys">加密字符串的密钥</param>
        /// <returns>加密后的字符串</returns>
        public string Encrypt(string keys, string plainText, string iv, string mode)
        {

            byte[] ptBytes = Encoding.UTF8.GetBytes(plainText);
            byte[] rv = Encrypt(keys, ptBytes, iv, mode);
            StringBuilder ret = new StringBuilder();
            foreach (byte b in rv)
            {
                ret.AppendFormat("{0:X2}", b);
            }
            return ret.ToString();
        }

        private byte[] Encrypt(string keys, byte[] ptBytes, string iv, string mode)
        {
            byte[] key = Encoding.UTF8.GetBytes(keys);
            BufferedBlockCipher cipher = null;
            if (mode.ToLower() == "ecb")
            {
                cipher = new PaddedBufferedBlockCipher(new EcbBlockCipher(engine), new Pkcs7Padding());
            }
            else if (mode.ToLower() == "cfb")
            {
                cipher = new PaddedBufferedBlockCipher(new CfbBlockCipher(engine, 8), new Pkcs7Padding());
            }
            else if (mode.ToLower() == "cbc")
            {
                cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(engine), new Pkcs7Padding());
            }

            if (mode.ToLower() == "ecb") cipher.Init(true, new DesParameters(key));
            else if (mode.ToLower() == "cfb") cipher.Init(true, new ParametersWithIV(new DesParameters(key), Encoding.UTF8.GetBytes(iv)));
            else if (mode.ToLower() == "cbc") cipher.Init(true, new ParametersWithIV(new DesParameters(key), Encoding.UTF8.GetBytes(iv)));
            byte[] rv = new byte[cipher.GetOutputSize(ptBytes.Length)];
            int tam = cipher.ProcessBytes(ptBytes, 0, ptBytes.Length, rv, 0);

            cipher.DoFinal(rv, tam);
            return rv;
        }

        /// <summary>
        /// 使用DES解密，key输入密码的时候，必须使用英文字符，区分大小写，且字符数量是8个，不能多也不能少
        /// </summary>
        /// <param name="cipherText">需要加密的字符串</param>
        /// <param name="keys">加密字符串的密钥</param>
        /// <returns>解密后的字符串</returns>
        public string Decrypt(string keys, string cipherText, string iv, string mode)
        {
            var inputByteArray = Convert.FromHexString(cipherText);
            var rv = Decrypt(keys, inputByteArray, iv, mode);
            return Encoding.UTF8.GetString(rv).Trim('\0');
        }

        private byte[] Decrypt(string keys, byte[] cipherText, string iv, string mode)
        {
            byte[] key = Encoding.UTF8.GetBytes(keys);
            BufferedBlockCipher cipher = null;
            if (mode.ToLower() == "ecb")
            {
                cipher = new PaddedBufferedBlockCipher(new EcbBlockCipher(engine), new Pkcs7Padding());
            }
            else if (mode.ToLower() == "cfb")
            {
                cipher = new PaddedBufferedBlockCipher(new CfbBlockCipher(engine, 8), new Pkcs7Padding());
            }
            else if (mode.ToLower() == "cbc")
            {
                cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(engine), new Pkcs7Padding());
            }
            if (mode.ToLower() == "ecb") cipher.Init(false, new DesParameters(key));
            else if (mode.ToLower() == "cfb") cipher.Init(false, new ParametersWithIV(new DesParameters(key), Encoding.UTF8.GetBytes(iv)));
            else if (mode.ToLower() == "cbc") cipher.Init(false, new ParametersWithIV(new DesParameters(key), Encoding.UTF8.GetBytes(iv)));
            byte[] rv = new byte[cipher.GetOutputSize(cipherText.Length)];
            int tam = cipher.ProcessBytes(cipherText, 0, cipherText.Length, rv, 0);

            cipher.DoFinal(rv, tam);
            return rv;
        }
    }

    public class BouncyCastleAes
    {

        IBlockCipher engine = new AesEngine();

        /// <summary>
        /// 使用DES加密，key输入密码的时候，必须使用英文字符，区分大小写，且字符数量是8个，不能多也不能少
        /// </summary>
        /// <param name="plainText">需要加密的字符串</param>
        /// <param name="keys">加密字符串的密钥</param>
        /// <returns>加密后的字符串</returns>
        public string Encrypt(string keys, string plainText, string iv, string mode)
        {

            byte[] ptBytes = Encoding.UTF8.GetBytes(plainText);
            byte[] rv = Encrypt(keys, ptBytes, iv, mode);
            StringBuilder ret = new StringBuilder();
            foreach (byte b in rv)
            {
                ret.AppendFormat("{0:X2}", b);
            }
            return ret.ToString();
        }

        private byte[] Encrypt(string keys, byte[] ptBytes, string iv, string mode)
        {
            byte[] key = Encoding.UTF8.GetBytes(keys);
            BufferedBlockCipher cipher = null;
            if (mode.ToLower() == "ecb")
            {
                cipher = new PaddedBufferedBlockCipher(new EcbBlockCipher(engine), new Pkcs7Padding());
            }
            else if (mode.ToLower() == "cfb")
            {
                cipher = new PaddedBufferedBlockCipher(new CfbBlockCipher(engine, 8), new Pkcs7Padding());
            }
            else if (mode.ToLower() == "cbc")
            {
                cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(engine), new Pkcs7Padding());
            }

            if (mode.ToLower() == "ecb") cipher.Init(true, new DesParameters(key));
            else if (mode.ToLower() == "cfb") cipher.Init(true, new ParametersWithIV(new DesParameters(key), Encoding.UTF8.GetBytes(iv)));
            else if (mode.ToLower() == "cbc") cipher.Init(true, new ParametersWithIV(new DesParameters(key), Encoding.UTF8.GetBytes(iv)));
            byte[] rv = new byte[cipher.GetOutputSize(ptBytes.Length)];
            int tam = cipher.ProcessBytes(ptBytes, 0, ptBytes.Length, rv, 0);

            cipher.DoFinal(rv, tam);
            return rv;
        }

        /// <summary>
        /// 使用DES解密，key输入密码的时候，必须使用英文字符，区分大小写，且字符数量是8个，不能多也不能少
        /// </summary>
        /// <param name="cipherText">需要加密的字符串</param>
        /// <param name="keys">加密字符串的密钥</param>
        /// <returns>解密后的字符串</returns>
        public string Decrypt(string keys, string cipherText, string iv, string mode)
        {
            var inputByteArray = Convert.FromHexString(cipherText);
            var rv = Decrypt(keys, inputByteArray, iv, mode);
            return Encoding.UTF8.GetString(rv).Trim('\0');
        }

        private byte[] Decrypt(string keys, byte[] cipherText, string iv, string mode)
        {
            byte[] key = Encoding.UTF8.GetBytes(keys);
            BufferedBlockCipher cipher = null;
            if (mode.ToLower() == "ecb")
            {
                cipher = new PaddedBufferedBlockCipher(new EcbBlockCipher(engine), new Pkcs7Padding());
            }
            else if (mode.ToLower() == "cfb")
            {
                cipher = new PaddedBufferedBlockCipher(new CfbBlockCipher(engine, 8), new Pkcs7Padding());
            }
            else if (mode.ToLower() == "cbc")
            {
                cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(engine), new Pkcs7Padding());
            }
            if (mode.ToLower() == "ecb") cipher.Init(false, new DesParameters(key));
            else if (mode.ToLower() == "cfb") cipher.Init(false, new ParametersWithIV(new DesParameters(key), Encoding.UTF8.GetBytes(iv)));
            else if (mode.ToLower() == "cbc") cipher.Init(false, new ParametersWithIV(new DesParameters(key), Encoding.UTF8.GetBytes(iv)));
            byte[] rv = new byte[cipher.GetOutputSize(cipherText.Length)];
            int tam = cipher.ProcessBytes(cipherText, 0, cipherText.Length, rv, 0);

            cipher.DoFinal(rv, tam);
            return rv;
        }
    }
}
